package com.example.perftool2;

import android.util.Log;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class CpuTool {

    private static final String TAG = CpuTool.class.getSimpleName();

    private HashMap<Integer, AppInfo> runningApps;

    /**
     * TODO 不知道为什么是这样的输出，没有显示数据那一行
     *
     * 10-24 15:27:41.410 11192 11192 I CpuTool : exec command:top -b -n 1 -p 7206
     * 10-24 15:27:41.698 11192 11192 I ShellTool3: shellExec: Tasks: 0 total,   0 running,   0 sleeping,   0 stopped,   0 zombie
     * 10-24 15:27:41.698 11192 11192 I ShellTool3:   Mem:  7458880K total,  6864792K used,   594088K free,     2700K buffers
     * 10-24 15:27:41.698 11192 11192 I ShellTool3:  Swap:  4194300K total,   115452K used,  4078848K free,  1849568K cached
     * 10-24 15:27:41.698 11192 11192 I ShellTool3: 800%cpu   0%user   0%nice   0%sys 800%idle   0%iow   0%irq   0%sirq   0%host
     * 10-24 15:27:41.698 11192 11192 I ShellTool3:    PID USER         PR  NI VIRT  RES  SHR S[%CPU] %MEM     TIME+ ARGS
     * 10-24 15:27:41.699 11192 11192 I CpuTool : exec command DONE
     *
     * @param runningApps
     * @param pids
     */
    public void getData(HashMap<Integer, AppInfo> runningApps, int[] pids) {
        this.runningApps = runningApps;
//        String command = "dumpsys cpuinfo";
        String command = "top -b -n 1 -p " + pids[0];
//        String command = "ps -o %CPU,PID,NAME -p " + pids[0];
//        String command = "cal";

        Log.i(TAG,"exec  command:" + command);
//        execTopCommand(command, pids);  //主要是这条语句，字符串中是命令
//        OriginShellUtils.CommandResult commandResult = OriginShellUtils.execCommand("ps -o %CPU,PID,NAME -p " + pids[0], false);
        OriginShellUtils.CommandResult commandResult = OriginShellUtils.execCommand(command, false);
        Log.i(TAG,"result1.result = " + commandResult.result);
        Log.i(TAG,"result1.successMsg = " + commandResult.successMsg);		// 有用的信息在这里，可以打印出来看看
        Log.i(TAG,"result1.errorMsg = " + commandResult.errorMsg);

//        ShellTool3.shellExec(command);
        Log.i(TAG,"exec command DONE");
    }

    private String concatPids(int[] pids) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < pids.length; i++) {
            if (i > 0) {
                sb.append(" ");
            }
            sb.append(pids[i]);
        }
        return sb.toString();
    }
    public static final String COMMAND_EXIT = "exit\n";
    public static final String COMMAND_LINE_END = "\n";
    public void execTopCommand(String command, int[] pids) {
        ArrayList<String> pidList = new ArrayList<>();
        for (int i = 0; i < pids.length; i++) {
            pidList.add("" + pids[i]);
        }
        Process process = null;
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        DataOutputStream os = null;

        try {
            process = Runtime.getRuntime().exec("sh");
            os = new DataOutputStream(process.getOutputStream());
            // donnot use os.writeBytes(commmand), avoid chinese charset
            // error
            os.write(command.getBytes());
            os.writeBytes(COMMAND_LINE_END);
            os.flush();

            os.write("cal".getBytes());
            os.writeBytes(COMMAND_LINE_END);
            os.flush();

            os.writeBytes(COMMAND_EXIT);
            os.flush();
            process.waitFor();

            InputStreamReader reader = new InputStreamReader(process.getInputStream());

            //Log.i(TAG, "successResult reader getEncoding:" + reader.getEncoding());
            successResult = new BufferedReader(reader);
            errorResult = new BufferedReader(new InputStreamReader(
                    process.getErrorStream()));
            String stringLine;
            int lineNum = 0;
            while ((stringLine = successResult.readLine()) != null) {
                Log.i(TAG, "stringLine:" + stringLine);
                int isContainPid = isCpuLine(pidList, stringLine);
                if (isContainPid > 0) {
                    Log.i(TAG, "successResult readLine, contain true");
                    updateUsage(isContainPid, parseCpuUsage(stringLine));
                } else {
                    Log.i(TAG, "successResult readLine, contain false");
                }
            }
            String stringLineError;
            while ((stringLineError = errorResult.readLine()) != null) {
                Log.i(TAG, "stringLineError:" + stringLineError);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (successResult != null) {
                    successResult.close();
                }
                if (errorResult != null) {
                    errorResult.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (process != null) {
                process.destroy();
            }
        }
    }

    public void execTopCommandReadbyte(String command, int[] pids) {
        ArrayList<String> pidList = new ArrayList<>();
        for (int i = 0; i < pids.length; i++) {
            pidList.add("" + pids[i]);
        }
        Process process = null;
        DataOutputStream os = null;

        try {
            process = Runtime.getRuntime().exec("sh");
            os = new DataOutputStream(process.getOutputStream());
            // donnot use os.writeBytes(commmand), avoid chinese charset
            // error
            os.write(command.getBytes());
            os.writeBytes(COMMAND_LINE_END);
            os.flush();
            os.writeBytes(COMMAND_EXIT);
            os.flush();
            process.waitFor();

            byte[] buf = new byte[128];
            InputStream inputStream = process.getInputStream();
            while (inputStream.read(buf, 0, 128) != -1) {
                String test = new String(buf);
                Log.i(TAG,"execTopCommandReadbyte test:" + test);
                for (int i = 0; i < 128; i++) {
                    Log.i(TAG, "execTopCommandReadbyte, item[" + i + "] = " + buf[i]);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (process != null) {
                process.destroy();
            }
        }
    }

    // from monitor
    private void execCmdLog(File redirectFile, List<String> cmd) {
        ProcessBuilder processBuilder = new ProcessBuilder(cmd);
        processBuilder.redirectOutput(redirectFile);
        processBuilder.redirectError(redirectFile);
        try {
            Log.i(TAG, "prepare exec " + cmd.get(0));
            Process process = processBuilder.start();
            process.waitFor();
        } catch (IOException | InterruptedException e) {
            Log.e(TAG, "execCmdLog error", e);
        }
    }

    private void parseString(String str) {
        int len = str.length();
        byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
        for (int i = 0; i < bytes.length; i++) {
            Log.i(TAG, "parseCpuString, bytes[" + i + "] = " + bytes[i]);
        }
    }

    private String parseCpuUsage(String line) {
        Log.i(TAG, "parseCpuUsage, line = " + line);
        String[] splitArray = line.split(" ");
        for (int i = 0; i < splitArray.length; i++) {
            String splitOne = splitArray[i];
            Log.i(TAG, "parseCpuUsage, item[" + i + "] = " + splitOne);
        }
        if (splitArray.length < 22) return "-1.0";
        return splitArray[21];
    }

    private int isCpuLine(ArrayList<String> pidList, String result) {
        for (String pid : pidList) {
            Log.i(TAG, "isCpuLine, pid:" + pid + ".");
            Log.i(TAG, "isCpuLine, read line:" + result + ".");
            if (result.contains(pid)) return Integer.parseInt(pid);
        }
        return -1;
    }

    private void updateUsage(int pid, String usage) {
        for (Map.Entry<Integer, AppInfo> entry : runningApps.entrySet()) {
            AppInfo value = entry.getValue();
            if (pid == value.getPid()) {
                value.setDumpsysCpuUsage(usage);
                break;
            }
        }
    }
}
